/* $Revision: $ $Date: $
 * 
 * Copyright (C) 2009 Robert Stephan
 * 
 * This file is part of *** CaCaO - Card Catalogs Online ***
 *
 * CaCaO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CaCao is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package cacao.client;

import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import cacao.client.data.CaCaOHelper;
import cacao.client.data.CatalogObject;
import cacao.client.data.ItemDetailsObject;
import cacao.client.data.SearchResultObject;
import cacao.client.ui.CaCaOIconImageBundle;
import cacao.client.ui.CaCaOMainComposite;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class CaCaO implements EntryPoint {
	private CaCaODataServiceAsync dataService;
	private CaCaOSessionServiceAsync sessionService;
	private CaCaOMainComposite cmpCaCaO;

	private HashMap<String, String> properties;

	private int catalogSelectionIndex = -1;
	private List<CatalogObject> catalogs;
	private SearchResultObject searchResult;
	private ItemDetailsObject currentItem = null;
	private CaCaOMessages messages;
	private CaCaOIconImageBundle cacaoIconIB;
	
	private boolean rezoom=false;

	public CaCaO() {
	}

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		messages = GWT.create(CaCaOMessages.class);
		dataService = (CaCaODataServiceAsync) GWT
				.create(CaCaODataService.class);
		((ServiceDefTarget) dataService).setServiceEntryPoint(GWT
				.getModuleBaseURL()
				+ "data");
		sessionService = (CaCaOSessionServiceAsync) GWT
				.create(CaCaOSessionService.class);
		((ServiceDefTarget) sessionService).setServiceEntryPoint(GWT
				.getModuleBaseURL()
				+ "session");

		cmpCaCaO = new CaCaOMainComposite(this);
		cmpCaCaO.setWidth("100%");
		cmpCaCaO.setHeight("100%");
		RootPanel.get().add(cmpCaCaO);

		catalogs = new Vector<CatalogObject>();
		searchResult = new SearchResultObject();

		AsyncCallback<List<CatalogObject>> callback = new AsyncCallback<List<CatalogObject>>() {
			public void onSuccess(List<CatalogObject> result) {
				catalogs.clear();
				if(result.size()>0){
				for (CatalogObject co : result) {
					catalogs.add(co);
				}
				selectOtherCatalogAndSearch(0, null);

				Timer t = new Timer() {
					public void run() {
						loadCardFromRequest();
					}
				};
				t.schedule(500);
				}
			}

			public void onFailure(Throwable caught) {
				Window.alert("Database connection failed.");
			}
		};
		dataService.retrieveCatalogs(callback);

		properties = new HashMap<String, String>();
		AsyncCallback<HashMap<String, String>> callback2 = new AsyncCallback<HashMap<String, String>>() {
			public void onSuccess(HashMap<String, String> result) {
				properties = result;
				cmpCaCaO.updateUI();
				
			}

			public void onFailure(Throwable caught) {
				Window.alert("Local properties could not be retrieved.");
			}
		};
		sessionService.retrieveClientProperties(callback2);
	}

	private void loadCardFromRequest() {
		// Document.get().getURL().contains("?card=")
		String id = Window.Location.getParameter("card");
		if (id != null) {
			final String catalog = id.substring(0, id.indexOf("_"));
			final String counter = id.substring(id.indexOf("_") + 1);
			for (int i = 0; i < getCatalogs().size(); i++) {
				if (getCatalogs().get(i).getCode().equals(catalog)) {
					selectOtherCatalogAndSearch(i, null);
					int newCount = Integer.parseInt(counter);
					int minCount = getCurrentCatalog().getFirstItemID();
					int maxCount = getCurrentCatalog().getLastItemID();
					if (newCount < minCount) {
						newCount = minCount;
					}
					if (newCount > maxCount) {
						newCount = maxCount;
					}
					final int c = newCount;
					Timer t = new Timer() {
						public void run() {
							changeCurrentItem(CaCaOHelper.generateImageID(
									catalog, c, counter.length()));
						}
					};
					t.schedule(500);
					break;
				}
			}
		}
	}
	
	@SuppressWarnings("unused")
	private void queryFromRequest() {
		// Document.get().getURL().contains("?card=")
		String query = Window.Location.getParameter("query");
		String catalog = Window.Location.getParameter("catalog"); 
		if (query != null && catalog!=null) {
			for (int i = 0; i < getCatalogs().size(); i++) {
				if (getCatalogs().get(i).getCode().equals(catalog)) {
					selectOtherCatalogAndSearch(i, query);
				}
			}
		}
	}

	public CaCaOIconImageBundle getIconImageBundle() {
		if (cacaoIconIB == null) {
			cacaoIconIB = GWT.create(CaCaOIconImageBundle.class);
		}
		return cacaoIconIB;
	}

	public int getCatalogSelectionIndex() {
		return catalogSelectionIndex;
	}

	public List<CatalogObject> getCatalogs() {
		return catalogs;
	}

	public CatalogObject getCurrentCatalog() {
		if (catalogSelectionIndex == -1)
			return null;
		return catalogs.get(catalogSelectionIndex);
	}

	/**
	 * changes the catalog and executes a search
	 * @param index - the index of the catalog, that should be used
	 * @param query - the query string or null;
	 */
	public void selectOtherCatalogAndSearch(int index, String query) {
		if(query==null){ query="";}
		if (catalogSelectionIndex != index) {
			catalogSelectionIndex = index;
			searchResult = new SearchResultObject();
			if (index < catalogs.size()) {
				// CatalogObject catalog = catalogs.get(catalogSelectionIndex);
				// changeCurrentItem(CaCaOHelper.generateImageID(catalog.getCode(),
				// catalog.getFirstItemID(), catalog.getItemIDLength()));

				AsyncCallback<SearchResultObject> callback = new AsyncCallback<SearchResultObject>() {
					public void onSuccess(SearchResultObject result) {
						searchResult = result;
						searchResult.setResult(null);
						changeCurrentItem(null);
						setRezoom(true);
						updateUI();
					}

					public void onFailure(Throwable caught) {
						Window.alert("Error while executing search.");
					}
				};
				dataService.search(catalogs.get(catalogSelectionIndex)
						.getCode(), query, callback);

			}
		}
	}

	public SearchResultObject getSearchResult() {
		return searchResult;
	}

	public ItemDetailsObject getCurrentItem() {
		return currentItem;
	}

	public CaCaOMessages getMessages() {
		return messages;
	}

	public void updateUI() {
		cmpCaCaO.updateUI();
	}

	protected void changeCurrentItem(String id) {
		AsyncCallback<ItemDetailsObject> callback = new AsyncCallback<ItemDetailsObject>() {
			public void onSuccess(ItemDetailsObject result) {
				currentItem = result;
				updateUI();
			}

			public void onFailure(Throwable caught) {
				Window.alert("Error while switching catalog entry.");
			}
		};
		dataService.retrieveItemDetails(id, callback);

	}

	public void doSearch(String parameter) {
		AsyncCallback<SearchResultObject> callback = new AsyncCallback<SearchResultObject>() {
			public void onSuccess(SearchResultObject result) {
				searchResult = result;
				changeCurrentItem(result.getImageID());
			}

			public void onFailure(Throwable caught) {
				Window.alert("Error while executing search.");
			}
		};
		dataService.search(catalogs.get(catalogSelectionIndex).getCode(),
				parameter, callback);
	}

	public void turnPage(int steps) {
		int count = 0;
		String catalog = getCurrentCatalog().getCode();
		if (currentItem != null) {
			String id = currentItem.getId();
			String counter = id.substring(id.indexOf("_") + 1);
			count = Integer.parseInt(counter);
		} else {
			count = getCurrentCatalog().getFirstItemID();
		}

		int minCount = getCurrentCatalog().getFirstItemID();
		int maxCount = getCurrentCatalog().getLastItemID();
		int newCount = count + steps;
		if (newCount < minCount) {
			newCount = minCount;
		}
		if (newCount > maxCount) {
			newCount = maxCount;
		}
		changeCurrentItem(CaCaOHelper.generateImageID(catalog, newCount,
				getCurrentCatalog().getItemIDLength()));

	}

	public CaCaODataServiceAsync getDataService() {
		return dataService;
	}

	public CaCaOSessionServiceAsync getSessionService() {
		return sessionService;
	}

	public HashMap<String, String> getProperties() {
		return properties;
	}

	public boolean isRezoom() {
		return rezoom;
	}

	public void setRezoom(boolean rezoom) {
		this.rezoom = rezoom;
	}
}
